package com.alks.function.service.impl.biocontrol.deptwork;

import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.utils.DatabaseUtils.DatabaseUtils;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.ObjectUtils;
import com.alks.common.utils.beanutils.StringUtils;
import com.alks.entity.data.entity.*;
import com.alks.entity.data.enums.biocontrol.CollectTypeEnum;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.function.data.dto.biocontrol.deptwork.ProdStaticDto;
import com.alks.function.data.dto.biocontrol.deptwork.ProdTempBackDto;
import com.alks.function.data.dto.biocontrol.deptwork.ProdTempDto;
import com.alks.function.data.request.biocontrol.deptwork.ProdDetailRequest;
import com.alks.function.data.request.biocontrol.deptwork.ProdTempRequest;
import com.alks.function.data.vo.biocontrol.deptwork.ProdStaticVo;
import com.alks.function.mapper.biocontrol.deptwork.PcExportPlanDetailMapper;
import com.alks.function.mapper.biocontrol.deptwork.PcFinanceApReconciliationMapper;
import com.alks.function.mapper.biocontrol.deptwork.PcFinishOemOutDetailMapper;
import com.alks.function.mapper.biocontrol.deptwork.PcOmeLotHeadMapper;
import com.alks.function.mapper.pcfactorywork.PcDhLotHeadMapper;
import com.alks.function.service.biocontrol.deptwork.IProdCollectService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.Page;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author MS
 * @since 2024/8/3上午10:11
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ProdCollectServiceImpl implements IProdCollectService {
    private final PcOmeLotHeadMapper omeMapper;
    private final PcFinishOemOutDetailMapper omeDetailMapper;
    private final PcFinanceApReconciliationMapper financeApMapper;
    private final PcExportPlanDetailMapper exportPlanDetailMapper;
    private final PcDhLotHeadMapper dhHeadMapper;


    @Override
    @AutoPageAop
    public ResponseInfo tempQuery(ProdTempRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        /*防止SQL注入*/
        DatabaseUtils.sqlCheck(request.getGroupField());
        DatabaseUtils.sqlCheck(request.getOrderField());
        /*获取数据*/
        List<ProdTempDto> dto = omeMapper.tempQuery(request, companyId);
        Page<ProdTempDto> page = (Page<ProdTempDto>) dto;
        Map<String, Object> sum = omeMapper.tempSumQuery(request, companyId);
        /*封装返回*/
        Map<String, Object> map = new HashMap<>(3);
        map.put("dto", dto);
        map.put("total", page.getTotal());
        map.put("sum", sum);
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo stats(ProdTempRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        /*获取数据*/
        ProdStaticVo staticVo = omeMapper.tempStatsQuery(request, companyId);
        if (ObjectUtils.isNull(staticVo)) {
            return ResponseInfo.ok(new ProdStaticDto());
        }
        return ResponseInfo.ok(staticVo.change2Vertical());
    }

    @Override
    public ResponseInfo tempBack(ProdTempRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        /*排序字段检核*/
        List<String> groupField = request.getGroupField();
        if (ArrayUtils.isEmpyt(groupField)) {
            return ResponseInfo.ok();
        }
        /*获取回显数据*/
        List<ProdTempBackDto> tempBacks = omeMapper.tempBackQuery(request, companyId);
        /*处理数据格式*/
        List<Field> fields = new ArrayList<>(groupField.size());
        try {
            for (String fieldName : groupField) {
                Field field = ProdTempBackDto.class.getDeclaredField(fieldName);
                field.setAccessible(true);
                fields.add(field);
            }
            List<ProdTempBackDto> dto = new ArrayList<>();
            Map<String, ProdTempBackDto> map = new HashMap<>();
            for (ProdTempBackDto tempBack : tempBacks) {
                ProdTempBackDto prefixRecord = null;
                for (int i = 0; i < groupField.size(); i++) {
                    prefixRecord = setNode(tempBack, fields.get(i),
                            ObjectUtils.isNull(prefixRecord) ? "" : prefixRecord.getPrefix(), map,
                            ObjectUtils.isNull(prefixRecord) ? dto : prefixRecord.getChildren(),
                            (i + 1 == groupField.size()), groupField.get(i));
                }
            }
            return ResponseInfo.ok(dto);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            return ResponseInfo.error("无效的分组字段");
        }
    }

    @Override
    @AutoPageAop
    public ResponseInfo detailQuery(ProdDetailRequest request) {
        String companyId = UserIdThread.get().getCompanyId();
        /*入参类型处理*/
        request.setCollectType(CollectTypeEnum.getTypeCodeByName(request.getCollectType()));
        /*获取数据*/
        LambdaQueryWrapper<PcFinishOemOutDetail> wrapper = new LambdaQueryWrapper<PcFinishOemOutDetail>()
                .eq(PcFinishOemOutDetail::getLotNo, request.getFactoryLotNo())
                .eq(StringUtil.isNotBlank(request.getCollectType()), PcFinishOemOutDetail::getCollectType, request.getCollectType())
                .eq(StringUtil.isNotBlank(request.getPoNo()), PcFinishOemOutDetail::getPoNo, request.getPoNo())
                .eq(PcFinishOemOutDetail::getCompanyId, companyId);
        List<PcFinishOemOutDetail> outDetails = omeDetailMapper.selectList(wrapper);
        Page<PcFinishOemOutDetail> page = (Page<PcFinishOemOutDetail>) outDetails;
        /*返回结果类型处理*/
        for (PcFinishOemOutDetail outDetail : outDetails) {
            outDetail.setCollectType(CollectTypeEnum.getTypeNameByCode(outDetail.getCollectType()));
        }
        /*封装返回*/
        Map<String, Object> map = new HashMap<>(2);
        map.put("dto", outDetails);
        map.put("total", page.getTotal());
        return ResponseInfo.ok(map);
    }

    @Override
    public ResponseInfo detailDelete(PcFinishOemOutDetail request) {
        String companyId = UserIdThread.get().getCompanyId();
        /*类型转换*/
        request.setCollectType(CollectTypeEnum.getTypeCodeByName(request.getCollectType()));
        /*数据检核*/
        LambdaQueryWrapper<PcFinishOemOutDetail> wrapper = new LambdaQueryWrapper<PcFinishOemOutDetail>()
                .eq(PcFinishOemOutDetail::getLotNo, request.getLotNo())
                .eq(PcFinishOemOutDetail::getSysDate, request.getSysDate())
                .eq(PcFinishOemOutDetail::getSysUser, request.getSysUser())
                .eq(PcFinishOemOutDetail::getPairQty, request.getPairQty())
                .eq(PcFinishOemOutDetail::getVendorNo, request.getVendorNo())
                .eq(PcFinishOemOutDetail::getCollectTime, request.getCollectTime())
                .eq(PcFinishOemOutDetail::getCollectType,request.getCollectType())
                .eq(PcFinishOemOutDetail::getCompanyId, companyId)
                .last("LIMIT 1");
        PcFinishOemOutDetail outDetail = omeDetailMapper.selectOne(wrapper);
        LambdaQueryWrapper<PcExportPlanDetail> exportPlanWrapper = new LambdaQueryWrapper<PcExportPlanDetail>()
                .eq(PcExportPlanDetail::getInvoiceNo, outDetail.getInvoiceNo())
                .eq(PcExportPlanDetail::getCompanyId, companyId);
        Integer exportCount = exportPlanDetailMapper.selectCount(exportPlanWrapper);
        if (exportCount > 0) {
            return ResponseInfo.error("存在船务作业明细数据,不能删除");
        }
        LambdaQueryWrapper<PcFinanceApReconciliation> financeWrapper = new LambdaQueryWrapper<PcFinanceApReconciliation>()
                .eq(PcFinanceApReconciliation::getInvoiceNo, outDetail.getInvoiceNo())
                .eq(PcFinanceApReconciliation::getFactoryLotNo, outDetail.getLotNo())
                .eq(PcFinanceApReconciliation::getAoaCfm, "Y")
                .eq(PcFinanceApReconciliation::getCompanyId, companyId);
        Integer count = financeApMapper.selectCount(financeWrapper);
        if (count > 0) {
            return ResponseInfo.error("数量已检核,不能删除");
        }
        /*删除对应数据*/
        omeDetailMapper.delete(wrapper);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo outAdd(PcFinishOemOutDetail request, String collectType) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String companyId = tokenDTO.getCompanyId();
        String userName = tokenDTO.getUserName();
        /*判断入参*/
        if (StringUtil.isBlank(request.getLotNo())) {
            return ResponseInfo.error("指令不能为空");
        }
        if (StringUtil.isBlank(request.getVendorNo())) {
            return ResponseInfo.error("厂商不能为空");
        }
        if (StringUtils.isNull(request.getCollectTime())) {
            return ResponseInfo.error("出库日期不能为空");
        }
        if (request.getCollectTime().isAfter(LocalDateTime.now())) {
            return ResponseInfo.error("出货时间不能大于当前日期");
        }
        if (StringUtils.isEmpty(request.getContainerNo()) || StringUtils.isEmpty(request.getInvoiceNo())) {
            return ResponseInfo.error("柜号和发票号不能为空");
        }
        /*船务操作判断*/
        LambdaQueryWrapper<PcExportPlanDetail> exportPlanWrapper = new LambdaQueryWrapper<PcExportPlanDetail>()
                .eq(PcExportPlanDetail::getInvoiceNo, request.getInvoiceNo())
                .eq(PcExportPlanDetail::getCfmFlag, "Y")
                .eq(PcExportPlanDetail::getCompanyId, companyId);
        Integer exportCount = exportPlanDetailMapper.selectCount(exportPlanWrapper);
        if (exportCount > 0) {
            return ResponseInfo.error("该发票号已被船务检核");
        }
        /*补充数据*/
        request.setCompanyId(companyId);
        request.setSysUser(userName);
        request.setSysDate(LocalDateTime.now());
        request.setCollectType(collectType);
        /*写入明细*/
        omeDetailMapper.insert(request);
        return ResponseInfo.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseInfo update(PcOmeLotHead request) {
        String companyId = UserIdThread.get().getCompanyId();
        String y = "Y";
        String thisCompany = "RS";
        /*定位数据*/
        PcOmeLotHead ome;
        LambdaUpdateWrapper<PcOmeLotHead> omeWrapper;
        try {
            omeWrapper = new LambdaUpdateWrapper<PcOmeLotHead>()
                    .eq(PcOmeLotHead::getFactoryLotNo, request.getFactoryLotNo())
                    .eq(PcOmeLotHead::getCompanyId, companyId);
            ome = omeMapper.selectOne(omeWrapper);
        }
        /*检核数据是否满足更新条件*/
        catch (MyBatisSystemException e) {
            return ResponseInfo.error("数据异常：该指令不唯一");
        }
        if (ObjectUtils.isNull(ome)) {
            return ResponseInfo.error("该指令不存在");
        }
        if (y.equals(ome.getComplete())) {
            return ResponseInfo.error("该指令已结案");
        }
        /*完成标志位更新*/
        complete(request);
        if (thisCompany.equals(ome.getVendorNo())) {
            PcDhLotHead dh;
            LambdaUpdateWrapper<PcDhLotHead> dhWrapper;
            try {
                dhWrapper = new LambdaUpdateWrapper<PcDhLotHead>()
                        .eq(PcDhLotHead::getLotNo, request.getLotNo())
                        .eq(PcDhLotHead::getCompanyId, companyId);
                dh = dhHeadMapper.selectOne(dhWrapper);
            }
            /*检核数据是否满足更新条件*/ catch (MyBatisSystemException e) {
                return ResponseInfo.error("数据异常：该指令不唯一");
            }
            if (ObjectUtils.isNull(dh)) {
                return ResponseInfo.error("该指令不存在");
            }
            /*本公司数据更新*/
            if (dh.getOrderQty().compareTo(request.getCraftQty()) < 0 ||
                    dh.getOrderQty().compareTo(request.getCutQty()) < 0 ||
                    dh.getOrderQty().compareTo(request.getFinishQty()) < 0 ||
                    dh.getOrderQty().compareTo(request.getMatchQty()) < 0 ||
                    dh.getOrderQty().compareTo(request.getInsoleQty()) < 0 ||
                    dh.getOrderQty().compareTo(request.getOutSoleQty()) < 0 ||
                    dh.getOrderQty().compareTo(request.getStitchQty()) < 0) {
                return ResponseInfo.error("进度数量不能大于订单数量");
            }
            /*数据更新*/
            dhWrapper.set(PcDhLotHead::getComplete,request.getComplete())
                    .set(PcDhLotHead::getCraftQty, request.getCraftQty())
                    .set(PcDhLotHead::getCutQty, request.getCutQty())
                    .set(PcDhLotHead::getFinishQty, request.getFinishQty())
                    .set(PcDhLotHead::getMatchQty, request.getMatchQty())
                    .set(PcDhLotHead::getInsoleQty, request.getInsoleQty())
                    .set(PcDhLotHead::getOutSoleQty, request.getOutSoleQty())
                    .set(PcDhLotHead::getStitchQty, request.getStitchQty());
            omeWrapper.set(PcOmeLotHead::getRemark, request.getRemark());
            dhHeadMapper.update(null, dhWrapper);
        } else {
            /*其他公司数据更新*/
            if (ome.getOrderQty().compareTo(request.getCraftQty()) < 0 ||
                    ome.getOrderQty().compareTo(request.getCutQty()) < 0 ||
                    ome.getOrderQty().compareTo(request.getFinishQty()) < 0 ||
                    ome.getOrderQty().compareTo(request.getMatchQty()) < 0 ||
                    ome.getOrderQty().compareTo(request.getInsoleQty()) < 0 ||
                    ome.getOrderQty().compareTo(request.getOutSoleQty()) < 0 ||
                    ome.getOrderQty().compareTo(request.getStitchQty()) < 0) {
                return ResponseInfo.error("进度数量不能大于订单数量");
            }
            /*数据更新*/
            omeWrapper.set(PcOmeLotHead::getComplete,request.getComplete())
                    .set(PcOmeLotHead::getCraftQty, request.getCraftQty())
                    .set(PcOmeLotHead::getCutQty, request.getCutQty())
                    .set(PcOmeLotHead::getFinishQty, request.getFinishQty())
                    .set(PcOmeLotHead::getMatchQty, request.getMatchQty())
                    .set(PcOmeLotHead::getInsoleQty, request.getInsoleQty())
                    .set(PcOmeLotHead::getOutSoleQty, request.getOutSoleQty())
                    .set(PcOmeLotHead::getStitchQty, request.getStitchQty())
                    .set(PcOmeLotHead::getRemark, request.getRemark());
        }
        omeWrapper.set(PcOmeLotHead::getComplete,request.getComplete())
                .set(PcOmeLotHead::getCutSample, request.getCutSample())
                .set(PcOmeLotHead::getAntenatalSample, request.getAntenatalSample())
                .set(PcOmeLotHead::getTryOnSample, request.getTryOnSample())
                .set(PcOmeLotHead::getTestSample, request.getTestSample())
                .set(PcOmeLotHead::getCfsSample, request.getCfsSample())
                .set(PcOmeLotHead::getRawMaterial, request.getRawMaterial())
                .set(PcOmeLotHead::getShoelace, request.getShoelace());
        log.error("\n错误接口：update\n错误原因：{}",request.getComplete());
        omeMapper.update(null, omeWrapper);
        return ResponseInfo.ok();
    }

    /**
     * 构建树形结构
     *
     * @param tempBack 当前节点
     * @param field    分组字段
     * @param prefix   前缀
     * @param map      树形结构
     * @param dto      返回值
     * @param leaf     是否是叶子节点
     * @param type     分组字段
     * @return 返回当前节点
     * @throws IllegalAccessException 反射异常
     */
    private ProdTempBackDto setNode(ProdTempBackDto tempBack, Field field, String prefix, Map<String, ProdTempBackDto> map, List<ProdTempBackDto> dto, boolean leaf, String type) throws IllegalAccessException {
        //MS TODO 2024/8/8 : 看不懂思密达
        String title = (String) field.get(tempBack);
        prefix = StringUtil.isBlank(prefix) ? title : prefix + "-" + title;
        ProdTempBackDto treeBack = map.get(prefix);
        if (ObjectUtils.isNull(treeBack)) {
            treeBack = new ProdTempBackDto();
            if (!leaf) {
                treeBack.setChildren(new ArrayList<>());
            } else {
                treeBack = tempBack;
            }
            treeBack.setTitle(title);
            treeBack.setLeaf(leaf);
            treeBack.setPrefix(prefix);
            treeBack.setType(type);
            map.put(prefix, treeBack);
            dto.add(treeBack);
        }
        treeBack.setCountNum(treeBack.getCountNum() + tempBack.getCountNum());
        treeBack.setOrderQty((treeBack.getOrderQty() == null ? BigDecimal.ZERO : treeBack.getOrderQty()).add(tempBack.getOrderQty() == null ? BigDecimal.ZERO : tempBack.getOrderQty()));
        return treeBack;
    }

    /**
     * 结案标志位更新
     * @param request 入参
     */
    private void complete(PcOmeLotHead request){
        String y = "1";
        String n = "0";
        if (y.equals(request.getCutSample())
        && y.equals(request.getAntenatalSample())
        && y.equals(request.getTryOnSample())
        && y.equals(request.getTestSample())
        && y.equals(request.getCfsSample())
        && y.equals(request.getRawMaterial())
        && y.equals(request.getShoelace())
        ){
            request.setComplete(y);
        }else {
            request.setComplete(n);
        }
    }
}
